﻿namespace NTLib.Core.Manipulators
{
    using NTLib.Core.Args;
    using NTLib.Core.ScopeLock;
    using System;
    using System.Runtime.CompilerServices;

    /// <summary>
    /// Simple accessor to a value;
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class SimpleAccessor<T> : IAccessor<T>
    {
        #region Fiedls

        private T _fields = default(T);

        #endregion

        #region Properties

        /// <summary>
        /// Gets a value indicating whether this instance can set a value.
        /// </summary>
        /// <value>
        ///   <c>true</c> if this instance can set; otherwise, <c>false</c>.
        /// </value>
        // [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool CanSet => true;

        /// <summary>
        /// Gets the type of the content.
        /// </summary>
        // [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public Type ContentType => typeof(T);

        #endregion

        #region Event

        /// <summary>
        /// Occurs when the value changed.
        /// </summary>
        public event Action<ValueChangedEventArgs<T>> ValueChanged;

        #endregion

        #region Methods

        /// <summary>
        /// Gets the value.
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public T Get() => this._fields;

        /// <summary>
        /// Gets the scoped.
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public ScopeLockItem<T> GetScoped() => new ScopeLockItem<T>(this._fields, null);

        /// <summary>
        /// Sets the specified value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="force">Force the refresh of the value</param>
        /// <returns>
        /// return <c>true</c> if the value have been changed; otherwise <c>false</c>
        /// </returns>
        public bool Set(T value, bool force = false)
        {
            if (force || !object.ReferenceEquals(this._fields, value) || !object.Equals(value, this._fields))
            {
                var old = this._fields;
                this._fields = value;

                if (ValueChanged != null)
                    ValueChanged(new ValueChangedEventArgs<T>(old, value));

                return true;
            }
            return false;
        }

        #endregion
    }
}
